//////////////////////////////////////////////////////////////////////////
#pragma once


template< typename T, typename V > inline
const T Math::Clamp( const T value, const V low, const V high )
{
	return( (value > low) ? (value < high) ? value : high : low );
}


template< typename T, typename V > inline
const T Math::Lerp( const T a, const T b, const V per )
{
	return( a + (b-a)*per );
}


template< typename T, typename M > inline
const T Math::Hermite( const T& v1, const T& t1, const T& v2, const T& t2, const M s )
{
	const T		s2	=	s*s;
	const T		s3	=	s2*s;
	const T		b0	=	(2*s3) - (3*s2) + 1,
				b1	=	-(2*s3) + (3*s2),
				b2	=	(s3) - (2*s2) + s,
				b3	=	(s3) - (s2);

	return( b0*v1 + b1*v2 + b2*t1 + b3*t2 );
}


template< typename T > inline
const T Math::Smooth( const T value )
{
	return( ( T( 3.0 )-T( 2.0 ) * value ) * value * value );
}


template< typename T > inline
const T Math::Step( const T percentage, const T a )
{
	return( (percentage>=a) ? T(1) : T(0) );
}


template< typename T > inline
const T Math::Pulse( const T percentage, const T a, const T b )
{
	return( Math::Step( percentage, a ) - Math::Step( percentage, b ) );
}


template< typename T > inline
const T Math::SmoothStep( const T percentage, const T a, const T b )
{
	return( (percentage < ((T)0.0)) ? a : (percentage > ((T)1.0)) ? b : Math::Lerp( Math::Smooth( percentage ), a, b ) );
}


template< typename T, typename D > inline
const D Spline( const size_t count, const D knots[], const T x )
{
	// Coefficients.
	const D		CR00	=	-D(0.5);	const D		CR01	=	D(1.5);
	const D		CR02	=	-D(1.5);	const D		CR03	=	D(0.5);
	const D		CR10	=	D(1);		const D		CR11	=	-D(2.5);
	const D		CR12	=	D(2);		const D		CR13	=	-D(0.5);
	const D		CR20	=	-D(0.5);	const D		CR21	=	D(0);
	const D		CR22	=	D(0.5);		const D		CR23	=	D(0);
	const D		CR30	=	D(0);		const D		CR31	=	D(1);
	const D		CR32	=	D(0);		const D		CR33	=	D(0);

	int nspans	= count-3;

	if( nspans<1 )
	{
		assert( false );	// This is not right!
		return D(0);
	}

	T		cx		= Clamp< T >( x, 0, 1 );
	int		span	= (int)cx;

	if( span>=count-3 )
		span=count-3;
	cx -= span;

	D	c3	=	CR00*knots[span]	+	CR01*knots[span+1]	+
				CR02*knots[span+2]	+	CR03*knots[span+3];
	D	c2	=	CR10*knots[span]	+	CR11*knots[span+1]	+
				CR12*knots[span+2]	+	CR13*knots[span+3];
	D	c1	=	CR20*knots[span]	+	CR21*knots[span+1]	+
				CR22*knots[span+2]	+	CR23*knots[span+3];
	D	c0	=	CR30*knots[span]	+	CR31*knots[span+1]	+
				CR32*knots[span+2]	+	CR33*knots[span+3];

	return( ((c3*cx + c2)*cx + c1)*cx + c0 );
}


template< typename T, typename V > inline
const T Gamma( const T gamma, const V x )
{
	return( std::pow( x, T(1)/gamma ) );
}


template< typename T > inline
const T Bias( const T b, const T x )
{
	return( Pow( T( x ), Log( T( b ) ) / Log( T( 0.5 ) ) ) );
}


template< typename T > inline
const T Gain( const T g, const T x )
{
	if( x<T(0.5f) )
		return Bias(T(1)-g, 2*x)/T(2);
	else
		return T(1)-Bias(T(1)-g, T(2)-T(2)*x)/T(2);
}


template< typename T > inline
const T BoxStep( const T a, const T b, const T x )
{
	return( Clamp((x-a)/(b-a), T(0), T(1)) );
}
